/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.draw.model;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Line2D;
import java.util.List;

import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.UItools.GraphicsUtil;
import com.cburch.logisim.util.IntegerFactory;
import com.cburch.logisim.util.Strings;

class Line extends DrawingMember {
    static final int ON_LINE_THRESH = 4;
    
    private int x0;
    private int y0;
    private int x1;
    private int y1;
    private Bounds bounds;
    private int strokeWidth;
    private Color strokeColor;
    
    public Line(int x0, int y0, int x1, int y1) {
        this.x0 = x0;
        this.y0 = y0;
        this.x1 = x1;
        this.y1 = y1;
        bounds = Bounds.create(x0, y0, 0, 0).add(x1, y1);
        strokeWidth = 1;
        strokeColor = Color.BLACK;
    }
    
    public String getDisplayName() {
        return Strings.get("shapeLine", Strings.drawSource);
    }

    public List getAttributes() {
        return DrawingAttribute.ATTRS_STROKE;
    }
    
    public Object getValue(Attribute attr) {
        if(attr == DrawingAttribute.STROKE_COLOR) {
            return strokeColor;
        } else if(attr == DrawingAttribute.STROKE_WIDTH) {
            return IntegerFactory.create(strokeWidth);
        } else {
            return null;
        }
    }
    
    public void setAttrValue(Attribute attr, Object value) {
        if(attr == DrawingAttribute.STROKE_COLOR) {
            strokeColor = (Color) value;
        } else if(attr == DrawingAttribute.STROKE_WIDTH) {
            strokeWidth = ((Integer) value).intValue();
        }
    }
    
    public Bounds getBounds() {
        return bounds;
    }
    
    public boolean contains(Location loc) {
        double d = Line2D.ptLineDistSq(x0, y0, x1, y1, loc.getX(), loc.getY());
        int thresh = Math.max(ON_LINE_THRESH, strokeWidth / 2);
        return d < thresh * thresh;
    }
    
    /*
    private double distanceSquared(int xq, int yq) {
        int x0 = this.x0;
        int y0 = this.y0;
        int x1 = this.x1;
        int y1 = this.y1;
        int dx = x1 - x0;
        int dy = y1 - y0;
        int dxq0 = xq - x0;
        int dyq0 = yq - y0;
        int rNum = dxq0 * dx + dyq0 * dy;
        int rDen = dx * dx + dy * dy;
        
        if(rNum >= 0 && rNum <= rDen) {
            int sNum = (y0 - yq) * dx - (x0 - xq) * dy;
            return (double) (sNum * sNum) / rDen;
        } else {
            double d0 = dxq0 * dxq0 + dyq0 * dyq0;
            double d1 = (xq-x1)*(xq-x1) + (yq-y1)*(yq-y1);
            return Math.min(d0, d1);
        }
    }
    */
    
    public void translate(int dx, int dy) {
        x0 += dx;
        y0 += dy;
        x1 += dx;
        y1 += dy;
    }
    
    public void getHandles(List dest) {
        dest.clear();
        dest.add(Location.create(x0, y0));
        dest.add(Location.create(x1, y1));
    }
    
    public void getHandles(List dest, int handleIndex, int dx, int dy) {
        dest.clear();
        if(handleIndex < 0 || handleIndex >= 2) throw new IndexOutOfBoundsException();
        if(handleIndex == 0) dest.add(Location.create(x0 + dx, y0 + dy));
        else dest.add(Location.create(x0, y0));
        if(handleIndex == 1) dest.add(Location.create(x1 + dx, y1 + dy));
        else dest.add(Location.create(x1, y1));
    }
    
    public void moveHandle(int index, int dx, int dy) {
        switch(index) {
        case 0: x0 += dx; y0 += dy; break;
        case 1: x1 += dx; y1 += dy; break;
        default: throw new IndexOutOfBoundsException("" + index);
        }
        bounds = Bounds.create(x0, y0, 0, 0).add(x1, y1);
    }
    
    protected boolean setForStroke(Graphics g) {
        if(strokeWidth > 0) {
            GraphicsUtil.switchToWidth(g, strokeWidth);
            g.setColor(strokeColor);
            return true;
        } else {
            return false;
        }
    }
    
    public void draw(Graphics g, int xOffs, int yOffs) {
        if(setForStroke(g)) {
            g.drawLine(xOffs + x0, yOffs + y0, xOffs + x1, yOffs + y1);
        }
    }
    
    public void draw(Graphics g, int xOffs, int yOffs,
            int handleIndex, int dx, int dy) {
        if(setForStroke(g)) {
            int x0 = this.x0;
            int y0 = this.y0;
            int x1 = this.x1;
            int y1 = this.y1;
            switch(handleIndex) {
            case 0: x0 += dx; y0 += dy; break;
            case 1: x1 += dx; y1 += dy; break;
            default: throw new IndexOutOfBoundsException("" + handleIndex);
            }
            g.drawLine(xOffs + x0, yOffs + y0, xOffs + x1, yOffs + y1);
        }
    }

}
